/* 
 * File:   menu.c
 * Author: Marcel
 *
 * Created on 11. September 2012, 05:06
 */

#include <p18f2620.h>
#include "timer.h"
#include "vfd.h"
#include "button.h"
#include "uart.h"
#include "menu.h"
// Processes
#include "processes/onestep.h"
#include "processes/threestep.h"
#include "processes/yeast.h"



/* Globals */
unsigned char state, state_old, state_prev;         // Defines the state of the menu
unsigned char active, active_old;                   // Current selection
static unsigned char btn;               // Buttons' state
unsigned char run = 0;
unsigned char line_cur = 0, line_old = 255;
unsigned char text_only_line = 0;


/* Menu screens */
struct MenuEntry InitMenu[] = {
    { (const rom char*)"G\\h84rbox v0.1     2012", Text, 0xFF },
    { (const rom char*)"by Marcel von Kannen", Text, 0xFF }
};

struct MenuEntry MainMenu[] = {
    { (const rom char*)"1-Stufige F\\h81hrung",	Item, 0x02 },
    { (const rom char*)"3-Stufige F\\h81hrung",	Item, 0x03 },
    { (const rom char*)"Hefeteig",		Item, 0x04 }
};

struct MenuEntry CancelMenu[] = {
    { (const rom char*)"Abbrechen?", Text, 0xFF },
    { (const rom char*)"ENT = Ja  SCR = Nein", Text, 0xFF }
};

struct MenuEntry DoneMenu[] = {
    { (const rom char*)"!!! Teig fertig !!!", Text, 0xFF },
    { (const rom char*)"Taste dr\\h81cken", Text, 0xFF }
};

extern unsigned char timer_1s_flag;
void menu_statemachine(void) {
    btn = button_pressed(button_debounce());
    
    switch(state) {
        case 0x00:  // Init screen
            menu_show(InitMenu, 0, 0);
            if(timer_1s()) {
                state++;
                timer_1s_flag = 0;
            }
            break;
        case 0x01:  // Main menu
            menu_management(3, MainMenu);
            break;
        case 0x02:  // ONESTEP Duration One Menu
            onestep_one();
            break;
        case 0x03:  // ONESTEP RefreshStatus
            onestep_duration_one();
            break;
        case 0x04:  // ONESTEP Duration Two Menu
            onestep_two();
            break;
        case 0x05:  // ONESTEP FuehrungStatus
            onestep_duration_two();
            break;

        // Additional menus
        case 0xF0:  // Cancel menu
            menu_cancel();
            break;
        case 0xF1:  // Done menu
            menu_done();
            break;
    }
}

void menu_set_state(unsigned char s) {
    state = s;
    active_old = active;
    active = 0;
    line_cur = 0;
    run = 0;
}

void menu_cancel(void) {
    menu_show(CancelMenu, 0, 0);
    if(run == 0)
        run = 1;

    if(btn & BUTTON1) { // SCR - Keep program
        menu_set_state(state_prev);
    }
    else if(btn & BUTTON2) {    // ENT - Exit program
        menu_set_state(state_prev-1);
        timer_reset_countdown();
    }
}

void menu_done(void) {
    menu_show(DoneMenu, 0, 0);
    if(run == 0)
        run = 1;

    if((btn & BUTTON1) || (btn & BUTTON2)) { // Back to main menu
        menu_set_state(0x01);
        timer_reset_countdown();
    }
}

void menu_management(unsigned char menu_size, struct MenuEntry menu[]) {
    if(run == 0) {
	// Check if there's a description line, and then decide where to place
	// the selection symbol
	if(menu[0].Type == Text)
            text_only_line = 1;
	else
            text_only_line = 0;
        run = 1;
    }
    else {
        // Show menu itself
        menu_show(menu, &line_cur, &line_old);

        // Put select symbol on correct place and draw it
        if((active == 0) && (text_only_line == 0)) {
            vfd_pos_xy(0, 1); vfd_putc(' ');
            vfd_pos_xy(0, 0);
        }
        else {
            if(text_only_line == 0)
                vfd_pos_xy(0, 0); vfd_putc(' ');

            vfd_pos_xy(0, 1);
        }
        vfd_putc(0xFA);

        if(btn & BUTTON1) { // If BUTTON1 (=SCROLL) was pressed...
            if(active < menu_size-1) {  // Check if wer're not at the end of the menu list
                if(text_only_line) {
                    if(active >= menu_size-2) {
                        active = 0;
                        line_cur = 0;
                    }
                    else {
                        active++;
                        line_cur++;
                    }
                }
                else {  // If no text line
                    if(active >= 1)
                        line_cur++;
                    active++;
                }
            }
            else {  // If we're at the end of the menu list
                active = 0;
                line_cur = 0;
            }
        }
        else if(btn & BUTTON2) {    // If BUTTON2 (=ENTER) was pressed...
            if(menu[active+text_only_line].Type == Item) {  // Enter new screen
                menu_set_state(menu[active+text_only_line].state);
            }
            else if(menu[active+text_only_line].Type == Exit) {  // back to prev screen
                switch(state) {
                case 0x02:  // ONESTEP Duration One Menu
                    menu_set_state(0x01);
                    break;
                case 0x04:  // ONESTEP Duration Two Menu
                    menu_set_state(0x02);
                    break;
                }
            }
        }
    }
}

void menu_show(struct MenuEntry menu[], unsigned char* line_cur, unsigned char* line_old) {
    unsigned char i;
    unsigned char cur_line;
    unsigned char old_line;

    if(line_cur == 0) // If line_cur is null-pointer, show from first line
        cur_line = 0;
    else	// otherwise, show from line_cur value
        cur_line = *line_cur;
    if(line_old == 0)
        old_line = 0;
    else
        old_line = *line_old;

    if((state_old != state) || (old_line != cur_line)) {
        vfd_clear();
        //LATC ^= 0x02;
        i = 0;
        while(i < 2) {	// Only show 2 lines
            if((menu[i+(cur_line)].Type == Text) && (menu[i+(cur_line)].Type != Exit))	// If it's text
                vfd_pos_xy(0, i);
            else	// If its a selectable item
                vfd_pos_xy(2, i);

            vfd_putrs((const rom char*) menu[i+(cur_line)].Text);	// Print text
            i++;
        }
    state_old = state;
    if(line_old != 0)
        *line_old = cur_line;
    }
}

void menu_init(void) {
    // Set statemachine to Reset
    state = 0x00;
    state_prev = 0x00;
    state_old = 0xFF;

    active = 0x00;
    active_old = active;
}